package com.peas.platform.common.core.utils;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.peas.platform.common.core.configuration.RequestContext;
import com.peas.platform.common.core.configuration.RequestContextUtil;
import com.peas.platform.common.core.configuration.RequestContextUtilEnum;
import com.peas.platform.common.core.constant.Constants;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @author caizhh
 */
@Slf4j
public class RequestUtil {

    public static final List<String> ignoreHeader = Arrays.asList(
            "accept",
            "accept-encoding",
            "accept-language",
            "cache-control",
            "connection",
            "cookie",
            "content-length",
            "content-type",
            "host",
            "pragma",
            "referer");

    public static void initRequestId() {
        initRequestId(null, null, null, null, null, null, null);
    }

    public static void initRequestId(HttpServletRequest request) {
        initRequestId(null, null, null, null, null, null, request);
    }

    public static void initRequestId(String traceId, String sso_sessionid, String userId, String userCode, String account) {
        if (StrUtil.isBlank(traceId)) {
            traceId = MDC.get("traceId");
        }
        initRequestId(traceId, sso_sessionid, userId, userCode, account, null, null);
    }

    public static void initRequestId(String traceId, String sso_sessionid, String userId, String userCode, String account, String resourceCode) {
        if (StrUtil.isBlank(traceId)) {
            traceId = MDC.get("traceId");
        }
        initRequestId(traceId, sso_sessionid, userId, userCode, account, resourceCode, null);
    }

    public static void initRequestId(RequestContext rc) {
        if (StrUtil.isBlank(rc.getTraceId())) {
            rc.setTraceId(MDC.get("traceId"));
        }
        initRequestId(rc.getTraceId(), rc.getSsoSessionId(), rc.getUserId(), rc.getUserCode(), rc.getAccount(), rc.getResourceCode(), null);
    }

    public static void initRequestId(String traceId, String sso_sessionid, String userId, String userCode, String account, String resourceCode, HttpServletRequest request) {
        // requestId
        String requestId = traceId;
        if (StrUtil.isBlank(requestId) && request != null) {
            requestId = getValueFromRequestCookie(request, RequestContextUtilEnum.requestId);
        }
        if (StrUtil.isBlank(requestId)) {
            requestId = MDC.get("traceId");
        }
        if (StrUtil.isBlank(requestId)) {
            requestId = Constants.snowflake.nextIdStr();
            log.debug("requestId is null, generated:" + requestId);
        }
        MDC.put("traceId", requestId);
        MDC.put("requestId", requestId);
        if (StrUtil.isNotBlank(requestId)) {
            RequestContextUtil.getCurrentContext().put(RequestContextUtilEnum.requestId, requestId);
        }
        // sso_sessionid
        if (StrUtil.isBlank(sso_sessionid) && request != null) {
            sso_sessionid = getValueFromRequestCookie(request, RequestContextUtilEnum.sso_sessionid);
        }
        if (StrUtil.isBlank(sso_sessionid) && request != null) {
            sso_sessionid = getValueFromRequestHeader(request, RequestContextUtilEnum.sso_sessionid);
        }
        if (StrUtil.isNotBlank(sso_sessionid)) {
            RequestContextUtil.getCurrentContext().put(RequestContextUtilEnum.sso_sessionid, sso_sessionid);
        }
        // userId
        if (StrUtil.isBlank(userId) && request != null) {
            userId = getValueFromRequestCookie(request, RequestContextUtilEnum.userId);
        }
        if (StrUtil.isBlank(userId) && request != null) {
            userId = getValueFromRequestHeader(request, RequestContextUtilEnum.userId);
        }
        if (StrUtil.isNotBlank(userId)) {
            RequestContextUtil.getCurrentContext().put(RequestContextUtilEnum.userId, userId);
        }
        // userCode
        if (StrUtil.isBlank(userCode) && request != null) {
            userCode = getValueFromRequestCookie(request, RequestContextUtilEnum.userCode);
        }
        if (StrUtil.isBlank(userCode) && request != null) {
            userCode = getValueFromRequestHeader(request, RequestContextUtilEnum.userCode);
        }
        if (StrUtil.isNotBlank(userCode)) {
            RequestContextUtil.getCurrentContext().put(RequestContextUtilEnum.userCode, userCode);
        }
        // account
        if (StrUtil.isBlank(account) && request != null) {
            account = getValueFromRequestCookie(request, RequestContextUtilEnum.account);
        }
        if (StrUtil.isBlank(account) && request != null) {
            account = getValueFromRequestHeader(request, RequestContextUtilEnum.account);
        }
        if (StrUtil.isNotBlank(account)) {
            RequestContextUtil.getCurrentContext().put(RequestContextUtilEnum.account, account);
        }
        // userId
        if (StrUtil.isBlank(userId) && request != null) {
            userId = getValueFromRequestCookie(request, RequestContextUtilEnum.userId);
        }
        if (StrUtil.isBlank(userId) && request != null) {
            userId = getValueFromRequestHeader(request, RequestContextUtilEnum.userId);
        }
        if (StrUtil.isNotBlank(userId)) {
            RequestContextUtil.getCurrentContext().put(RequestContextUtilEnum.userId, userId);
        }
        // resourceCode
        if (StrUtil.isBlank(resourceCode) && request != null) {
            resourceCode = getValueFromRequestHeader(request, RequestContextUtilEnum.resourceCode);
        }
        if (StrUtil.isNotBlank(resourceCode)) {
            RequestContextUtil.getCurrentContext().put(RequestContextUtilEnum.resourceCode, resourceCode);
        }
        // application
        if (request != null) {
            RequestContextUtil.getCurrentContext().put(RequestContextUtilEnum.application, request.getHeader(RequestContextUtilEnum.application.name()));
        }
    }

    private static String getValueFromRequestHeader(HttpServletRequest request, RequestContextUtilEnum key) {
        String v = request.getHeader(key.name());
        if (StrUtil.isNotBlank(v)) {
            return v;
        }
        Enumeration<String> headers = request.getHeaderNames();
        log.debug("headers:" + headers);
        while (headers != null && headers.hasMoreElements()) {
            String name = headers.nextElement();
            if (StrUtil.equalsIgnoreCase(key.name(), name)) {
                return request.getHeader(name);
            }
        }
        return null;
    }

    private static String getValueFromRequestCookie(HttpServletRequest request, RequestContextUtilEnum key) {
        Assert.notNull(request, "数据错误");
        Assert.notNull(key, "key is null");
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                String name = cookie.getName();
                String value = cookie.getValue();
                if (StrUtil.equals(key.name(), name) && StrUtil.isNotBlank(value)) {
                    return value;
                }
            }
        }
        return request.getHeader(key.name());
    }

    public static void print(HttpServletRequest request) {
        log.info("【request】pathInfo:" + request.getPathInfo());
        log.info("【request】requestURI:" + request.getRequestURI());
        log.info("【request】requestURL:" + request.getRequestURL());
        log.info("【request】contextPath:" + request.getContextPath());
        log.info("【request】queryString:" + request.getQueryString());
        log.info("【request】method:" + request.getMethod());
        log.info("【request】authType:" + request.getAuthType());
        log.info("【request】pathTranslated:" + request.getPathTranslated());
        log.info("【request】remoteUser:" + request.getRemoteUser());
        log.info("【request】remoteAddr:" + request.getRemoteAddr());
        log.info("【request】remoteHost:" + request.getRemoteHost());
        log.info("【request】remotePort:" + request.getRemotePort());
        log.info("【request】servletPath:" + request.getServletPath());
        log.info("【request】requestedSessionId:" + request.getRequestedSessionId());
        log.info("【request】protocol:" + request.getProtocol());
        log.info("【request】serverName:" + request.getServerName());
        log.info("【request】serverPort:" + request.getServerPort());
        log.info("【request】scheme:" + request.getScheme());
        log.info("【request】contentType:" + request.getContentType());
        log.info("【request】localAddr:" + request.getLocalAddr());
        log.info("【request】localName:" + request.getLocalName());
        log.info("【request】localPort:" + request.getLocalPort());
        log.info("【request】parameterMap:" + JSONUtil.toJsonStr(request.getParameterMap()));
        log.info("【request】trailerFields:" + JSONUtil.toJsonStr(request.getTrailerFields()));
        Map<String, Cookie> cookie = new HashMap<>();
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie c : cookies) {
                cookie.put(c.getName(), c);
            }
        }
        log.info("【request】cookies:" + JSONUtil.toJsonStr(cookie));
        Map<String, String> header = new HashMap<>();
        Enumeration<String> headers = request.getHeaderNames();
        log.debug("headers:" + headers);
        while (headers != null && headers.hasMoreElements()) {
            String name = headers.nextElement();
            header.put(name, request.getHeader(name));
        }
        log.info("【request】header:" + JSONUtil.toJsonStr(header));
    }

}
